#include"list.h"
#include"interrupt.h"
#include"global.h"

/*kernal not check the elem is validate use assert ensure
 *element is validate
*/

void list_init(list* plist){
	plist->head.next=&plist->tail;
	plist->head.prev=&plist->tail;
	plist->tail.prev=&plist->head;
	plist->tail.next=&plist->head;
}

void list_insert_before(list_elem* before,list_elem* pelem){
	intr_status old_status=intr_disable();
	pelem->next=before;
	pelem->prev=before->prev;
	before->prev->next=pelem;
	before->prev=pelem;
	intr_set_status(old_status);
	return;
}

void list_append(list* plist,list_elem* pelem){
	intr_status old_status=intr_disable();
	pelem->next=&plist->tail;
	pelem->prev=plist->tail.prev;
	plist->tail.prev->next=pelem;
	plist->tail.prev=pelem;
	intr_set_status(old_status);
}

void list_remove(list_elem* pelem){
	intr_status old_status=intr_disable();
	pelem->prev->next=pelem->next;
	pelem->next->prev=pelem->prev;	
	pelem->next=NULL;
	pelem->prev=NULL;
	intr_set_status(old_status);
}

void list_push(list* plist,list_elem* pelem){
	intr_status old_status=intr_disable();
	pelem->next=plist->head.next;
	pelem->prev=&plist->head;
	plist->head.next->prev=pelem;
	plist->head.next=pelem;
	intr_set_status(old_status);
}

list_elem* list_pop(list* plist){
	intr_status old_status=intr_disable();
	list_elem* p=plist->head.next;
	plist->head.next=p->next;
	p->next->prev=&plist->head;
	p->next=NULL;
	p->prev=NULL;
	intr_set_status(old_status);
	return p;
}

bool list_empty(list* plist){
	return plist->head.next==&plist->tail ? true : false;
}

uint32_t list_len(list* plist){
	uint32_t i=0;
	list_elem* p=plist->head.next;
	while(p!=&plist->tail){
		i++;
		p=p->next;
	}
	return i;
}

list_elem* list_traversal(list* plist,list_call_back call_back,int arg){
	int i;
	list_elem* p;
	for(i=0,p=plist->head.next;p!=&plist->tail;i++,p=p->next){
		if(!call_back(p,arg)){
			return p;
		}
	}
	return NULL;
}

int elem_find(list* plist,list_elem* pelem){
	list_elem* p;
	p=plist->head.next;
	while(p!=&plist->tail){
		if(pelem==p)
			return 1;
		p=p->next;
	}
	return 0;
}
